package com.zmn.brs.business.impl.rule;

import com.alibaba.fastjson.JSONObject;
import com.zmn.brs.business.interfaces.rule.AlarmRuleBService;
import com.zmn.brs.common.constant.RedisKeyConst;
import com.zmn.brs.common.enums.EventTypeEnum;
import com.zmn.brs.common.enums.ExpressionEnum;
import com.zmn.brs.common.enums.ThresholdExpressionEnum;
import com.zmn.brs.common.enums.ThresholdTypeEnum;
import com.zmn.brs.model.bo.rule.CacheThresholdBO;
import com.zmn.brs.model.bo.rule.CustomRuleBO;
import com.zmn.brs.model.entity.event.Event;
import com.zmn.brs.model.entity.threshold.Threshold;
import com.zmn.brs.model.query.rule.EngineerRuleCustomQuery;
import com.zmn.brs.model.query.rule.OrderRuleCustomQuery;
import com.zmn.brs.model.vo.rule.ComparisonRuleVO;
import com.zmn.brs.model.vo.rule.QuantityRuleVO;
import com.zmn.brs.model.vo.rule.SalesRuleVO;
import com.zmn.brs.model.vo.rule.UnpaidRuleVO;
import com.zmn.brs.persistence.interfaces.event.EventDao;
import com.zmn.brs.persistence.interfaces.rule.AlarmRuleDao;
import com.zmn.brs.persistence.interfaces.rule.engineer.EngineerRuleDao;
import com.zmn.brs.persistence.interfaces.threshold.ThresholdDao;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 描述: 规则基础接口实现类
 *
 * @author chongw
 * @since  2021-06-24 15:55:07
 **/
@Slf4j
@Service
public class AlarmRuleBServiceImpl<T>  implements AlarmRuleBService<T>{

    private static final String TAG = "规则基础服务接口";

    @Resource
    private AlarmRuleDao alarmRuleDao;

    @Resource
    private EngineerRuleDao engineerRuleDao;

    @Resource
    private ThresholdDao thresholdDao;

    @Resource
    private EventDao eventDao;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 根据事件Id查询规则信息
     * @param eventId
     * @return
     */
    @Override
    public Integer findRuleIdByEventId(Integer eventId){
       Event event = eventDao.findById(eventId);
       if(event == null){
           return null;
       }
       List<Integer> ruleIds = Optional.ofNullable(alarmRuleDao.findRuleIdByEventCode(event.getEventCode())).orElse(new ArrayList<>());
       if(ruleIds.isEmpty()){
           return null;
       }
       return ruleIds.get(0);
    }

    /**
     * 按条件查询数据 不支持分页
     * @param query 查询对象
     * @return java.util.List<com.zmn.brs.model.bo.rule.OrderRuleBO>
     * @throws
     * @author chongw
     * @since 2021/06/24 11:17
     */
    @Override
    public List<CustomRuleBO> listPageOrderRuleByEventQuery(OrderRuleCustomQuery query){
        query.setTotalCount(alarmRuleDao.countOrderRulePageByEventQuery(query));
        return alarmRuleDao.listPageOrderRuleByEventQuery(query);
    }

    /**
     * 按条件查询数据 不支持分页
     * @param query 查询对象
     * @return java.util.List<com.zmn.brs.model.bo.rule.OrderRuleBO>
     * @throws
     * @author chongw
     * @since 2021/06/24 11:17
     */
    @Override
    public List<CustomRuleBO> listPageRuleByEventQuery(EngineerRuleCustomQuery query){
        query.setTotalCount(engineerRuleDao.countRulePageByEventQuery(query));
        return engineerRuleDao.listPageRuleByEventQuery(query);
    }

    /**
     * 按条件查询数据 不支持分页
     * @param query 查询对象
     * @return java.util.List<com.zmn.brs.model.bo.rule.OrderRuleBO>
     * @throws
     * @author chongw
     * @since 2021/06/24 11:17
     */
    @Override
    public List<CustomRuleBO> listOrderRuleByEventQuery(OrderRuleCustomQuery query){
        return alarmRuleDao.listOrderRuleByEventQuery(query);
    }

    /**
     * 按条件查询数据 不支持分页
     * @param query 查询对象
     * @return java.util.List<com.zmn.brs.model.bo.rule.CustomRuleBO>
     * @throws
     * @author chongw
     * @since 2021/06/24 11:17
     */
    @Override
    public List<CustomRuleBO> listRuleByEventQuery(EngineerRuleCustomQuery query){
        return engineerRuleDao.listRuleByEventQuery(query);
    }

    /**
     * 校验规则是否存在
     * @param query
     * @return
     */
    @Override
    public Integer countOrderRuleExistByQuery(OrderRuleCustomQuery query){
        return alarmRuleDao.countOrderRuleExistByQuery(query);
    }

    /**
     * 校验规则是否存在
     * @param query
     * @return
     */
    @Override
    public Integer countRuleExistByQuery(EngineerRuleCustomQuery query){
        return engineerRuleDao.countRuleExistByQuery(query);
    }

    /**
     * 保存事件公共阈值
     * @param event
     * @return
     */
    @Override
    public Integer upsertEventCommonRule(Event event){
        Integer ruleId = findRuleIdByEventId(event.getEventId());
        if(NumberUtil.isNullOrZero(ruleId)){
            log.error("[{}], 当前事件未找到规则ID为空，eventId: {}", TAG, event.getEventId());
            return 0;
        }
        Threshold threshold = thresholdDao.findCommonThresholdByRuleId(ruleId);
        Date now = DateUtil.getNow();
        Map<String, Object> comm = event.getCommon();
        //获取唯一key
        String uniqueNo = RedisKeyConst.getCacheRuleConfigRedisKey(event.getEventType(), ThresholdTypeEnum.COMMON.name().toLowerCase());
        comm.put("uniqueNo", uniqueNo);
        comm.put("ruleId", ruleId);
        AtomicReference<Integer> flag = new AtomicReference<>(0);
        //新增 写入缓存
        if(threshold == null){
            //阈值
            Threshold thresholdInsert = Threshold.builder()
                    .ruleId(ruleId)
                    .thresholdName("公共阈值")
                    .type(ThresholdTypeEnum.COMMON.getTypeId())
                    .expression(ThresholdExpressionEnum.ALL.getExpression())
                    .thresholdValue(JSONObject.toJSONString(comm))
                    .creater(event.getUpdater())
                    .updater(event.getUpdater())
                    .createTime(now)
                    .updateTime(now)
                    .build();

            flag.updateAndGet(v -> v + thresholdDao.insert(thresholdInsert));

        }
        //修改
        else{
            comm.put("thresholdId" , threshold.getThresholdId());
            Integer thresholdId = threshold.getThresholdId();
            Threshold thresholdUpdate = thresholdDao.findById(thresholdId);
            thresholdUpdate.setThresholdValue(JSONObject.toJSONString(comm));
            thresholdUpdate.setType(ThresholdTypeEnum.COMMON.getTypeId());
            thresholdUpdate.setUpdateTime(now);
            thresholdUpdate.setUpdater(event.getUpdater());

            flag.updateAndGet(v -> v + thresholdDao.updateByKey(thresholdUpdate));

        }
        if(flag.get() > 0) {
            //写入缓存
            this.cacheCommonRule(uniqueNo, JSONObject.toJSONString(comm));
        }
        return flag.get();
    }

    /**
     * 缓存监控规则配置
     * @param redisKey
     * @param eventId
     * @param thresholdId
     */
    @Override
    public void cacheRule(String redisKey, Integer eventId, Integer thresholdId){

        this.cacheRule(redisKey, null , eventId , thresholdId);
    }

    /**
     * 缓存监控规则配置
     * @param redisKey
     * @param oldRedisKey
     * @param eventId
     * @param thresholdId
     */
    @Override
    public void cacheRule(String redisKey, String oldRedisKey, Integer eventId, Integer thresholdId){
        //查询规则阈值
        Threshold threshold = thresholdDao.findById(thresholdId);
        //获取事件信息
        Event event = eventDao.findById(eventId);
        JSONObject object = JSONObject.parseObject(threshold.getThresholdValue());
        CacheThresholdBO thresholdBO = CacheThresholdBO.builder()
                .sceneId(event.getSceneId())
                .eventId(event.getEventId())
                .eventCode(event.getEventCode())
                .ruleId(threshold.getRuleId())
                .thresholdId(threshold.getThresholdId())
                .thresholdName(threshold.getThresholdName())
                .thresholdValue(threshold.getThresholdValue())
                .value(object.getDoubleValue("value"))
                .build();
        //删除原来的redis缓存
        if(oldRedisKey != null){
            redisTemplate.delete(oldRedisKey);
        }
        redisTemplate.opsForValue().set(redisKey , JSONObject.toJSONString(thresholdBO));
    }

    /**
     * 缓存监控规则公共阈值配置
     * @param redisKey
     * @param value
     */
    @Override
    public void cacheCommonRule(String redisKey, String value){
        //缓存规则公共阈值
        redisTemplate.opsForValue().set(redisKey , value);
    }

    /**
     * 初始化缓存监控规则
     * @author chongw
     * @since  2021-06-30 14:55:07
     */
    @Override
    public void initCacheRule(){
        try {
            log.info("[{}], 初始化监控规则配置开始！！！" ,TAG );
            List<CustomRuleBO> list = alarmRuleDao.listOrderRuleByEventQuery(OrderRuleCustomQuery.builder()
                    .build());
            list.forEach(o -> {

                Threshold threshold = Threshold.builder()
                        .thresholdId(o.getThresholdId())
                        .ruleId(o.getRuleId())
                        .thresholdValue(o.getThresholdValue())
                        .build();
                //缓存城市整单量
                if (EventTypeEnum.QUANTITY.getTypeId().equals(o.getEventType())) {
                    QuantityRuleVO quantityRuleVO = JSONObject.parseObject(o.getThresholdValue(), QuantityRuleVO.class);
                    String redisKey = RedisKeyConst.getCacheRuleConfigRedisKey(EventTypeEnum.QUANTITY.getTypeId() , quantityRuleVO.getCityId());
                    this.cacheRule(redisKey, o.getEventId(), threshold.getThresholdId());
                }
                //缓存人单比配置
                else if (EventTypeEnum.COMPARISON.getTypeId().equals(o.getEventType())) {
                    ComparisonRuleVO comparisonRuleVO = JSONObject.parseObject(o.getThresholdValue(), ComparisonRuleVO.class);
                    String redisKey = RedisKeyConst.getCacheRuleConfigRedisKey(EventTypeEnum.COMPARISON.getTypeId(), comparisonRuleVO.getCityId()
                            , comparisonRuleVO.getServGroupId());
                    this.cacheRule(redisKey, o.getEventId(), threshold.getThresholdId());
                }
                //缓存工程师收款未支付配置
                else if (EventTypeEnum.ENGINEER_UNPAID.getTypeId().equals(o.getEventType())) {
                    UnpaidRuleVO unpaidRuleVO = JSONObject.parseObject(o.getThresholdValue(), UnpaidRuleVO.class);
                    String redisKey = RedisKeyConst.getCacheRuleConfigRedisKey(EventTypeEnum.ENGINEER_UNPAID.getTypeId(), unpaidRuleVO.getOrgThrId());
                    this.cacheRule(redisKey, o.getEventId(), threshold.getThresholdId());
                }
                //缓存工程师派单客单价配置
                else if (EventTypeEnum.ENGINEER_SALES.getTypeId().equals(o.getEventType())) {
                    SalesRuleVO salesRuleVO = JSONObject.parseObject(o.getThresholdValue(), SalesRuleVO.class);
                    //获取唯一key
                    String redisKey = RedisKeyConst.getCacheRuleConfigRedisKey(EventTypeEnum.ENGINEER_SALES.getTypeId(), salesRuleVO.getOrgThrId() ,
                            ExpressionEnum.getExpressionEnum(salesRuleVO.getExpression()).name().toLowerCase()
                    );
                    this.cacheRule(redisKey, o.getEventId(), threshold.getThresholdId());
                }
                //缓存规则状态
                String redisKey = RedisKeyConst.getStatusRedisKey(RedisKeyConst.THRESHOLD_STATUS_REDIS_KEY, o.getThresholdId());
                redisTemplate.opsForValue().set(redisKey, o.getStatus());
            });
            log.info("[{}], 初始化监控规则配置完成！！！" ,TAG );
        }catch (Exception e){
            log.error("[{}], 初始化监控规则配置异常！！！，异常信息：{}" ,TAG , e);
        }
    }

}